import { _decorator, AudioClip, AudioSource, Component, EventTouch, Input, input, instantiate, Label, LabelComponent, log, math, Node, NodeEventType, Prefab, sys, tween, UITransform, v2, v3, Vec2 } from 'cc';
import { Tile } from './tile';
const { ccclass, property } = _decorator;

@ccclass('game')
export class game extends Component {
    @property(Node)
    startPanel: Node = null;    // 游戏界面中->右侧组件，通过拖拽node到此对象上。
    @property(Node)
    gamePanel: Node = null;
    @property(Node)
    overPanel: Node = null;

    @property(LabelComponent)
    txtLv: LabelComponent = null;
    @property(LabelComponent)
    txtScore: LabelComponent = null;
    @property(LabelComponent)
    txtBestScore: LabelComponent = null;
    @property(LabelComponent)
    txtBack: LabelComponent = null;

    @property(Node)
    ndParent: Node = null;
    @property(UITransform)
    ndParentTransform: UITransform = null;
    @property(Prefab)
    item: Prefab = null;
    @property(Prefab)
    itemBg: Prefab = null;
    @property(LabelComponent)
    txtOverScore: LabelComponent = null!;

    @property(AudioClip)
    soundMove: AudioClip = null!;
    @property(AudioClip)
    soundGetScore: AudioClip = null!;

    private userData: any = null;
    private jiange: number = 0;
    private itemWH: number = 0;
    private itemParentWh: number = 0;
    private array = [];

    private posStart;
    private posEnd;
    private gameType: number = 0;   // 记录在哪个游戏界面上

    start() {
        this.initPanel(); // 初始化面板
        this.startPanel.active = true; // 显示开始面板
        this.addTouch();
    }
    /**
     * 事件监听
     */
    private addTouch() {
        input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
        input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        input.on(Input.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
    }

    private onTouchStart(event) {
        if (this.gameType != 1)
            return;
        this.posStart = event.getLocation();
    }

    private onTouchMove(event) {
        if(this.gameType != 1)
            return;
    }

    private onTouchEnd(event) {
        if (this.gameType != 1)
            return;
        this.posEnd = event.getLocation();
        let xx = this.posEnd.x - this.posStart.x;
        let yy = this.posEnd.y - this.posStart.y;
        if (Math.abs(xx) < 10 && Math.abs(yy) < 10) {
            return
        }

        if (Math.abs(xx) > Math.abs(yy)) {
            if (xx > 0) {
                this.moveItem("right");
                console.log("向右滑动") // 向右滑动时的逻辑处理
            } else {
                this.moveItem("left");
                console.log("向左滑动") // 向左滑动时的逻辑处理
            }
        } else {
            if (yy > 0) {
                this.moveItem("up");
                console.log("向上滑动") // 向上滑动时的逻辑处理
            } else {
                this.moveItem("down");
                console.log("向下滑动") // 向下滑动时的逻辑处理
            }
        }

    }

    private moveItem(type: string) {
        let canMove: boolean = false;
        let isGetScore: boolean = false;
        switch (type) {
            case "right":
                for(let j = this.array.length -2; j>=0; j--) { // 从倒数第二列开始计算
                    for (let i=0; i<this.array.length; i++) {
                        for (let k =0; k<this.array.length; k++) {
                            if (j + 1 + k >= this.array.length)
                                continue; // 避免越界访问，因为j+1+k是向右移动的格子，可能越
                            if(this.array[i][j+1+k] == 0 && this.array[i][j+k] > 0) {
                                // 向右移动，右边的格子数值=左边的格子数值
                                this.array[i][j+1+k] = this.array[i][j+k];
                                // 左边的格子数值清0
                                this.array[i][j+k] = 0;
                                canMove = true;
                            } else if(this.array[i][j+1+k] == this.array[i][j+k] && this.array[i][j+k] > 0) {
                                // 找到分数相同的格子
                                this.array[i][j+1+k] += this.array[i][j+1+k]*2;
                                this.array[i][j+k] = 0;
                                canMove = true;
                                isGetScore = true;
                                this.updateScore(this.array[i][j+1+k]);
                            }
                        }
                    }
                }
                break;
            case "left":
                for (let j = 1; j < this.array.length; j++) {
                    for (let i = 0; i < this.array[j].length; i++) {
                        for (let k = 0; k < this.array.length; k++) {
                            if (j - 1 - k >= 0 && this.array[i][j - 1 - k] == 0 && this.array[i][j - k] > 0) {
                                //可以移动
                                this.array[i][j - 1 - k] = this.array[i][j - k];
                                this.array[i][j - k] = 0;
                                canMove = true;
                            }
                            else if (j - 1 - k >= 0 && this.array[i][j - 1 - k] == this.array[i][j - k] && this.array[i][j - k] > 0) {
                                //可以合成
                                this.array[i][j - 1 - k] = this.array[i][j - 1 - k] * 2;
                                this.array[i][j - k] = 0;
                                canMove = true;
                                isGetScore = true;
                                this.updateScore(this.array[i][j - 1 - k]);
                            }
                        }
                    }
                }                
                break;
            case "up":
                for (let i = this.array.length - 2; i >= 0; i--) {
                    for (let j = 0; j < this.array[i].length; j++) {
                        for (let k = 0; k < this.array.length; k++) {
                            if (i + 1 + k < this.array.length && this.array[i + 1 + k][j] == 0 && this.array[i + k][j] > 0) {
                                //可移动
                                this.array[i + 1 + k][j] = this.array[i + k][j];
                                this.array[i + k][j] = 0;
                                canMove = true;
                            }
                            else if (i + 1 + k < this.array.length && this.array[i + 1 + k][j] == this.array[i + k][j] && this.array[i + k][j] > 0) {
                                //可以合成
                                this.array[i + 1 + k][j] = this.array[i + 1 + k][j] * 2;
                                this.array[i + k][j] = 0;
                                canMove = true;
                                isGetScore = true;
                                this.updateScore(this.array[i + 1 + k][j]);
                            }
                        }
                    }
                }                
                break;
            case "down":
                for (let i = 1; i < this.array.length; i++) {
                    for (let j = 0; j < this.array[i].length; j++) {
                        for (let k = 0; k < this.array.length; k++) {
                            if (i - 1 - k >= 0 && this.array[i - 1 - k][j] == 0 && this.array[i - k][j] > 0) {
                                //可以移动
                                this.array[i - 1 - k][j] = this.array[i - k][j];
                                this.array[i - k][j] = 0;
                                canMove = true;
                            }
                            if (i - 1 - k >= 0 && this.array[i - 1 - k][j] == this.array[i - k][j] && this.array[i - k][j] > 0) {
                                //可以合成
                                this.array[i - 1 - k][j] = this.array[i - 1 - k][j] * 2;
                                this.array[i - k][j] = 0;
                                canMove = true;
                                isGetScore = true;
                                this.updateScore(this.array[i - 1 - k][j]);
                            }
                        }
                    }
                }                
                break;
                default:break;
        }
        if(canMove) {
            let ad: AudioSource = new AudioSource();
            if (isGetScore) {
                ad.playOneShot(this.soundGetScore);
            } else {
                ad.playOneShot(this.soundMove);
            }

            this.cleanAllItem();
            for (let i=0; i<this.array.length; i++) {
                for(let j=0; j<this.array[i].length; j++) {
                    // 找到有数值的格子记录下来
                    if(this.array[i][j] > 0) {
                        let pos = v2(i,j);
                        this.createItem(pos, this.array[i][j]);
                    } 
                }
            }
            // 随机生成一个格子
            this.addRandomArray();
        }
    }

    // 清理格子
    private cleanAllItem() {
        // 获取父容器的所有组件
        let children = this.ndParent.children;
        for(let i=children.length-1; i>=0; i--) {
            let tile = children[i].getComponent(Tile);
            if(tile) {
                this.ndParent.removeChild(children[i]);
            }
        }
    }

    private updateScore(score:number) {
        // 更新最高分
        this.userData.score += score;
        if (this.userData.score >= this.userData.bestScore) {
            this.userData.bestScore = this.userData.score;
        }
        // 刷新界面分数
        this.txtScore.string = this.userData.score + "";
        this.txtBestScore.string = this.userData.bestScore + "";
        // 保存用户数据
        this.saveUserInfo();
    }

    private onTouchCancel(event) {
        if(this.gameType != 1)
            return;
    }
 
    update(deltaTime: number) {

    }

    private initPanel() {
        this.startPanel.active = false;
        this.gamePanel.active = false;
        this.overPanel.active = false;
    }

    // 初始化游戏
    private init() {
        this.getUserInfo();
        this.updateView();
    }
    // 获取用户信息
    private getUserInfo() {
        this.userData = JSON.parse(sys.localStorage.getItem('userData'));
        if (this.userData == null) {
            this.userData = {
                lv: 5,
                score: 0,
                bestScore: 0,
                array: [],
                arr_histroy: [],
                backNum: 3
            }
        }
    }
    // 保存用户信息
    private saveUserInfo() {
        sys.localStorage.setItem("userData", JSON.stringify(this.userData));
    }

    // 刷新界面
    private updateView() {
        this.gameType = 1;
        let lv = this.userData.lv.toString();
        this.jiange = 5;
        this.itemWH = Math.round(640 / lv);
        this.itemParentWh = this.itemWH * lv + this.jiange * (lv - 1);
        this.ndParentTransform.width = this.itemParentWh;
        this.ndParentTransform.height = this.itemParentWh;
        this.addItemBg(lv);

        this.txtLv.string = lv + "x" + lv;
        this.txtScore.string = this.userData.score.toString();
        this.txtBestScore.string = this.userData.bestScore.toString();
        let len = this.userData.arr_histroy.length - 1;
        if (len <= 0) {
            len = 0;
        }
        if (len > this.userData.backNum) {
            len = this.userData.backNum;
        }

        this.txtBack.string = "撤回(" + len + ")";

        if (this.userData.array.length == 0) {
            this.initArray(lv); // 初始化数组
            // 随机产生一个数字
            this.addRandomArray();
        } else {
            // 处理撤销
            this.array = this.userData.array;
            for (let i = 0; i < this.array.length; i++) {
                for (let j = 0; j < this.array[i].length; j++) {
                    if (this.array[i][j] > 0) {
                        let pos = v2(i, j);
                        this.createItem(pos, this.array[i][j]);
                    }
                }
            }
        }
    }

    private initArray(lv: number) {
        this.array = [];
        for (let i=0; i<lv; i++) {
            this.array[i] = [];
        }

        for (let i=0; i<lv; i++) {
            for (let j=0; j<lv; j++) {
                this.array[i][j] = 0;
            }
        }
    }

    // 在空格子上随机增加数字
    private addRandomArray() {
        let arr_0 = []; // 获取所有的空数组
        for (let i=0; i<this.array.length; i++) {
            for(let j=0; j<this.array[i].length; j++) {
                if (this.array[i][j] == 0) {
                    arr_0.push(v2(i,j));// 坐标存储下来
                }
            }
        }

        // 随机在空格处生成一个2或者4
        if(arr_0.length != 0) {
            let i_random = Math.floor(Math.random() * arr_0.length); // 随机获取一个坐标，并向下取整
            let ii = arr_0[i_random].x;
            let jj = arr_0[i_random].y;
            let randomNum = Math.random()*10;
            if(randomNum < 2) {
                this.array[ii][jj] = 4;
            } else {
                this.array[ii][jj] = 2;
            }
            this.createItem(arr_0[i_random], this.array[ii][jj], true);
            this.onCheckOver();
        }
    }

    /**
     * 
     * @param pos 
     * @param num 
     * @param isAction 是否显示动画
     */
    private createItem(pos:Vec2, num:number, isAction:boolean = false) {
        let posStart = v2(-this.itemParentWh/2 + this.itemWH/2 + this.jiange, -this.itemParentWh/2 + this.itemWH/2 + this.jiange);
        let item = instantiate(this.item);  // 复制一个预制体
        let tile = item.getComponent(Tile);
        if (tile) {
            tile.init(num);
        }
        item.parent = this.ndParent;
        let itemTf:UITransform = item.getComponent(UITransform);
        itemTf.width = this.itemWH;
        itemTf.height = this.itemWH;
        let _x = posStart.x + (itemTf.width + this.jiange)*pos.x;
        let _y = posStart.y + (itemTf.height + this.jiange)*pos.y;
        item.position = v3(_x, _y, 0);
        if(isAction) {
            item.scale = v3(0,0,0);
            // TODO 以下显示效果
            tween(item).to(0.15, { scale: v3(1, 1, 1) }, {easing:"sineInOut"}).start();
        }
    }

    private addItemBg(lv: number) {
        let posStart = v2(-this.itemParentWh / 2 + this.itemWH / 2 + this.jiange, -this.itemParentWh / 2 + this.itemWH / 2 + this.jiange);
        for (let i = 0; i < lv; i++) {
            for (let j = 0; j < lv; j++) {
                // 创建预制体
                let itemBg = instantiate(this.itemBg);
                // 设置预制体的父对象
                itemBg.parent = this.ndParent;
                // UI变换组件
                let itemBgTf: UITransform = itemBg.getComponent(UITransform)!;
                itemBgTf.width = this.itemWH;
                itemBgTf.height = this.itemWH;
                let posX = posStart.x + (itemBgTf.width + this.jiange) * j;
                let posY = posStart.y + (itemBgTf.height + this.jiange) * i;
                itemBg.position = v3(posX, posY, 0);
            }
        }

    }

    // 点击事件
    private onStartButtonClick() {
        this.initPanel();
        this.gamePanel.active = true; // 显示游戏面板
        this.init();
    }

    // 重玩事件
    private onRestartButtonClick() {
        this.gameType = 1;
        this.userData.score = 0;
        this.userData.arr_histroy = [];
        this.txtBack.string = "撤回(0)";
        this.userData.backNum = 3;
        this.txtScore.string = "0";
        this.cleanAllItem();
        this.initArray(this.userData.lv);
        this.addRandomArray();
    }

    // 返回事件
    private onBackButtonClick() {
        let len = this.userData.arr_histroy.length;
        if (len >= 2 && this.userData.backNum > 0) {
            this.userData.arr_histroy.pop();
            let str_arr = this.userData.arr_histroy[len - 2];
            var arr = str_arr.split(",");
            this.cleanAllItem();
            let k_num = -1;
            for (let i = 0; i < this.array.length; i++) {
                for (let j = 0; j < this.array[i].length; j++) {
                    k_num++;
                    this.array[i][j] = parseInt(arr[k_num]);
                    if (this.array[i][j] > 0) {
                        let pos = v2(i, j);
                        this.createItem(pos, this.array[i][j]);
                    }
                }
            }
            this.userData.backNum--;
            let len1 = this.userData.arr_histroy.length - 1;
            if (len1 <= 0) {
                len1 = 0;
            }
            if (len1 > this.userData.backNum) {
                len1 = this.userData.backNum;
            }
            this.txtBack.string = "撤回(" + len1 + ")";
            this.saveUserInfo();
        }        
    }

    // 返回主界面
    private onBackToMainButtonClick() {
        this.initPanel();
        this.gameType = 0;
        this.startPanel.active = true; // 显示开始面板
        this.cleanAllItem();
        this.cleanAllItemBg()        
    }

    private onOverBtnRestartClick() {
        this.overPanel.active = false;
        this.gameType = 1;
        this.userData.score = 0;
        this.userData.arr_histroy = [];
        this.txtBack.string = "撤回(0)";
        this.userData.backNum = 3;
        this.txtScore.string = "0";
        this.cleanAllItem();
        this.initArray(this.userData.lv);
        this.addRandomArray();        
    }

    private onOverBtnHomeClick() {
        this.initPanel();
        this.gameType = 0;
        this.startPanel.active = true; // 显示开始面板
        this.cleanAllItem();
        this.cleanAllItemBg()                
    }

    private onCheckOver() {
        let isOver = true;

        for (let i = 0; i < this.array.length; i++) {
            for (let j = 0; j < this.array[i].length; j++) {
                if (this.array[i][j] == 0) {
                    isOver = false;
                }

            }
        }

        for (let i = 0; i < this.array.length; i++) {
            for (let j = 0; j < this.array[i].length; j++) {
                if (j + 1 < this.array.length && this.array[i][j] == this.array[i][j + 1]) {
                    isOver = false;
                }
                else if (i + 1 < this.array.length && this.array[i][j] == this.array[i + 1][j]) {
                    isOver = false;
                }
            }
        }
        if (isOver) {
            this.gameType = 2;
            this.overPanel.active = true;
            let gameOverScore = this.userData.score;
            this.txtOverScore.string = "获得" + gameOverScore + "分";
            this.userData.score = 0;
            this.userData.array = [];
            this.userData.arr_histroy = [];
            this.userData.backNum = 3;
            this.saveUserInfo();
        } else {
            this.userData.arr_histroy.push(this.array.join());
            this.userData.array = this.array;
            let len = this.userData.arr_histroy.length - 1;
            if (len > 10) {
                this.userData.arr_histroy.shift();
            }
            if (len > this.userData.backNum) {
                len = this.userData.backNum;
            }
            this.txtBack.string = "撤回(" + len + ")";
            this.saveUserInfo();
        }
    }

    private cleanAllItemBg() {
        let children = this.ndParent.children;
        for (let i = children.length - 1; i >= 0; i--) {
            let tile = children[i].getComponent(Tile);
            if (!tile) {
                this.ndParent.removeChild(children[i]);
            }
        }
    }
}
